/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is
 *
 * java-concurrency-presentation:
 * concurrency presentation tutorial.
 *
 * The Initial Developer of the Original Code is
 * Marco Antonio Villalobos, Jr.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): None.
 *
 * ***** END LICENSE BLOCK *****
 */

package presentation.concurrency.slides;

// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples

/**
 * This is a demonstration of how NOT to write multi-threaded programs.
 * It is a program that purposely causes deadlock between two threads that
 * are both trying to acquire locks for the same two resources.
 * To avoid this sort of deadlock when locking multiple resources, all threads
 * should always acquire their locks in the same order.
 **/
public class DeadLock {

    public static void main(String[] args) {
        // These are the two resource objects we'll try to get locks for
        final Object resource1 = "resource1";
        final Object resource2 = "resource2";
        // Here's the first thread.  It tries to lock resource1 then resource2
        Thread t1 = new Thread() {
            public void run() {
                // Lock resource 1
                synchronized(resource1) {
                    System.out.println("Thread 1: locked resource 1");

                    // Pause for a bit, simulating some file I/O or something.
                    // Basically, we just want to give the other thread a chance to
                    // run.  Threads and deadlock are asynchronous things, but we're
                    // trying to force deadlock to happen here...
                    try { Thread.sleep(50); } catch (InterruptedException e) {}

                    // Now wait 'till we can get a lock on resource 2
                    synchronized(resource2) {
                        System.out.println("Thread 1: locked resource 2");
                    }
                }
            }
        };

        // Here's the second thread.  It tries to lock resource2 then resource1
        Thread t2 = new Thread() {
            public void run() {
                // This thread locks resource 2 right away
                synchronized(resource2) {
                    System.out.println("Thread 2: locked resource 2");

                    // Then it pauses, for the same reason as the first thread does
                    try { Thread.sleep(50); } catch (InterruptedException e) {}

                    // Then it tries to lock resource1.  But wait!  Thread 1 locked
                    // resource1, and won't release it 'till it gets a lock on
                    // resource2.  This thread holds the lock on resource2, and won't
                    // release it 'till it gets resource1.  We're at an impasse. Neither
                    // thread can run, and the program freezes up.
                    synchronized(resource1) {
                        System.out.println("Thread 2: locked resource 1");
                    }
                }
            }
        };

        // Start the two threads. If all goes as planned, deadlock will occur,
        // and the program will never exit.
        t1.start();
        t2.start();
    }
}
